package com.example.nutritionmate.service;

import com.example.nutritionmate.dto.*;
import com.example.nutritionmate.entity.*;
import com.example.nutritionmate.repository.MealRecordRepository;
import com.example.nutritionmate.repository.MealRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MealService {

    @Autowired
    private MealRecordRepository mealRecordRepository;

    @Autowired
    private MealRepository mealRepository;

    // 获取某用户的所有 MealRecords 及相关信息
    public List<MealRecord> getMealRecordsByUser(User user) {
        return mealRecordRepository.findByUser(user);
    }

    /**
     * 获取用户在指定日期的所有四餐饮食记录。
     *
     * @param user 用户实体
     * @param date 查询的日期
     * @return DayMealDTO 包含四餐的饮食记录
     */
    public DayMealDTO getDayMealsByUserAndDate(User user, LocalDate date) {
        // 从数据库中检索特定用户和日期的所有MealRecord
        List<MealRecord> mealRecords = mealRecordRepository.findByUserAndMeal_Date(user, date);

        // 按餐食类型分组（Breakfast, Lunch, Dinner, Snack）
        Map<String, List<MealRecord>> groupedMeals = mealRecords.stream()
                .collect(Collectors.groupingBy(mr -> mapMealType(mr.getMeal().getMealType())));

        // 定义四餐的顺序
        List<String> mealTypes = Arrays.asList("Breakfast", "Lunch", "Dinner", "Snack");

        // 初始化DayMealDTO
        DayMealDTO dayMealDTO = new DayMealDTO();
        dayMealDTO.setLocalDate(date);

        // 为每种餐食类型设置对应的MealRecordDTO列表
        dayMealDTO.setBreakfast(mapMealRecordDTOList(groupedMeals.getOrDefault("Breakfast", new ArrayList<>())));
        dayMealDTO.setLunch(mapMealRecordDTOList(groupedMeals.getOrDefault("Lunch", new ArrayList<>())));
        dayMealDTO.setDinner(mapMealRecordDTOList(groupedMeals.getOrDefault("Dinner", new ArrayList<>())));
        dayMealDTO.setSnacks(mapMealRecordDTOList(groupedMeals.getOrDefault("Snack", new ArrayList<>())));

        return dayMealDTO;
    }

    /**
     * 将餐食类型代码映射为餐食名称。
     *
     * @param code 餐食类型代码（"0", "1", "2", "3"）
     * @return    餐食名称（"Breakfast", "Lunch", "Dinner", "Snack"）
     */
    private String mapMealType(Integer code) {
        switch (code) {
            case 0:
                return "Breakfast";
            case 1:
                return "Lunch";
            case 2:
                return "Dinner";
            case 3:
                return "Snack";
            default:
                return "Unknown";
        }
    }

    /**
     * 将MealRecord列表转换为MealRecordDTO列表。
     *
     * @param mealRecords MealRecord实体列表
     * @return           MealRecordDTO列表
     */
    private List<MealRecordDTO> mapMealRecordDTOList(List<MealRecord> mealRecords) {
        return mealRecords.stream()
                .map(this::mapMealRecordToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 将一个MealRecord实体转换为MealRecordDTO。
     *
     * @param mealRecord MealRecord实体
     * @return          MealRecordDTO
     */
    private MealRecordDTO mapMealRecordToDTO(MealRecord mealRecord) {
        MealRecordDTO dto = new MealRecordDTO();
        dto.setRecordId(mealRecord.getRecordId());
        dto.setMealType(mapMealType(mealRecord.getMeal().getMealType()));
        dto.setDate(mealRecord.getMeal().getDate());

        // 将MealNutrition转换为NutrientDTO
        List<NutrientDTO> nutrients = mealRecord.getMealNutritions().stream()
                .map(this::mapMealNutritionToDTO)
                .collect(Collectors.toList());
        dto.setNutrients(nutrients);

        return dto;
    }

    /**
     * 将MealNutrition实体转换为NutrientDTO。
     *
     * @param mealNutrition MealNutrition实体
     * @return              NutrientDTO
     */
    private NutrientDTO mapMealNutritionToDTO(MealNutrition mealNutrition) {
        NutrientDTO dto = new NutrientDTO();
        dto.setName(mealNutrition.getNutritionFact().getNutritionName());
        dto.setNameEn(mealNutrition.getNutritionFact().getNutritionNameEn());
        dto.setUnit(mealNutrition.getNutritionFact().getUnit());
        dto.setAmount(mealNutrition.getAmount());
        return dto;
    }
}
